<?php

namespace App\Console\Dispatch;


use App\Models\News;
use App\Models\NewsCate;
use App\Models\NewsDesc;
use App\Models\NewsTag;
use App\Models\SiteCate;
use App\Models\SiteTag;
use App\Service\Translate;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;


class Base extends Command
{
    /**
     * 采集舆情文章
     *
     * 参数与选项的区别
     *      在执行命令时，参数必须严格按定义时的顺序输入，不需输入参数名，只需输入参数的值即可。
     *      输入选项则必须带选项名，且选项名前须加 -- 前缀（选项简写字母前加 -），选项可按任意顺序输入
     */

    // 请求 以及参数
    // protected $signature = 'command:name {param1} {param2}';  // 必填参数
    // protected $signature = 'command:name {参数名?} {参数名=默认值} {参数名? : 参数说明}';  // 可选参数
    // protected $signature = 'command:name {--选项名} {--选项名=} {--选项名=默认值} {--简写字母|选项名} {--选项名 : 选项说明}';  // 选项

    protected $signature   = 'command:dispatch-';
    protected $description = '各个地方的快讯采集操作';
    protected $curl;  // 采集 实例化
    protected $qiniu;  // 七牛云的相关配置
    protected $error;
    protected $errorno;
    protected $code;
    protected $ctime;  // 当前时间

    // 初始化
    public function __construct()
    {
        $this->init();

        parent::__construct();
    }

    // 初始化
    public function init() { }


    // 页面展示消息
    protected function showMsg($msg, $code = 400)
    {
        $this->errorno = $code;
        if($code == 500){
            $this->error($msg);
            // die;
        } else{
            $this->comment($msg);
        }
    }

    // 页面展示消息
    protected function showError($error, $code = 400)
    {
        $this->errorno = $code;
        $this->error($error);
        if($code == 500){
            // die;
        }
    }

    // 页面展示消息 并结束
    protected function showDie($error)
    {
        $this->error($error);
        die;
    }

    // 保存列表  如果有特殊处理 则改写`saveLists`方法
    protected function saveLists($list, $filter)
    {
        foreach($list as $_row){
            $this->saveRow($_row, $filter);
        } // 循环采集结束

        return true;
    }

    // 保存一篇
    protected function saveRow($row, $filter = [], $field = 'cn_keyword')
    {
        if(empty($row["url"]) || empty($row["site"]) || empty($row["desc"])){
            return $this->showError('保存字段不全！');
        }

        // 参数
        $time   = $this->getCurrentTime();
        $ptime  = $row['time'] ?? $time;  // 发布时间
        $_title = $row["title"] ?? '';
        // 参数
        // 采集的快讯 只有描述与标题
        //   快讯有单独的关键词，可能有，也可能没有
        $_description = $row["desc"];
        $cn_keywords  = $row["cn_keywords"] ?? [];
        $en_keywords  = $row["en_keywords"] ?? [];
        // 过滤不要采集的内容
        $_is = $this->filterSystem($_title, $_description);
        if($_is){
            return true;
        }

        // 过滤不要采集的内容
        $_is = $this->filterContent($_title, $_description, $filter);
        if($_is){
            return true;
        }

        $newsDb = new News();
        $descDb = new NewsDesc();
        $cateDb = new NewsCate();
        $tagDb  = new NewsTag();
        // 判断是否已经采集
        $info = $newsDb->where(["from_site" => $row["site"], "from_url" => $row["url"]])->select(["id"])->first();
        if(!empty($info)){
            return true;
        }

        // 对比栏目
        $cateKeywords = $this->getCateKeywords($field);
        $cateResult   = $this->keywordToCate($cateKeywords, $_description, $ptime, false);
        $_cateIds     = $cateResult['cate_ids'];
        $_cateKeyword = $cateResult['keywords'];
        // 对比标签
        $tagResult   = $this->keywordToTag($_cateKeyword, $cn_keywords, $en_keywords, $ptime);
        $_tagIds     = $tagResult['tag_ids'];  // 采集快讯 不匹配到标签
        $tc_keywords = $tagResult['tc_keywords'];
        $cn_keywords = $tagResult['cn_keywords'];
        $en_keywords = $tagResult['en_keywords'];

        // 上传图片 images
        $_qiImg = [];
        /*if(!empty($row['images'])){
            foreach($row['images'] as $_img){
                // 上传图片
                $_src   = $this->downImage($_img['uri'], 'https://www.fx678.com/');
                $_qiniu = $this->toQiniu($_src);
                if($_qiniu){
                    $_qiImg = [$_qiniu];
                }
            }
        }*/


        // 标签：手动输入+栏目标签库 随机3个 写入数据库
        // 标签就是 keywords

        ####################################################################################
        try{
            if($field == 'cn_keyword'){
                $en_title       = $this->translate($_title, 'en');
                $cn_title       = $_title;
                $en_description = $this->translate($_description, 'en');
                $cn_description = $_description;
            } elseif($field == 'en_keyword'){
                $en_title       = $_title;
                $cn_title       = $this->translate($_title, 'cn');
                $en_description = $_description;
                $cn_description = $this->translate($_description, 'cn');
            }
        } catch(\Exception $e){
            return $this->showError($e->getMessage());
        }

        //$en_title       = '$this->translate($_title, \'en\')';
        //$en_description = '$this->translate($_description, \'en\')';
        //$en_keywords = $this->translate($_keywords, 'en');
        //$tc_keywords = $this->translate($_keywords, 'tc');

        // 插入的操作
        $_cates = $_tags = [];
        $insert = [
            //'uid'            => '21',
            //'id'           => 'required',
            //'author'       => 'required',
            //'ip'           => 'required',
            //'ip_address'   => 'required',
            //'cn_description' => $_description,
            //'en_description' => $en_description,
            //'tc_description' => $tc_description,
            //'tc_title'       => $tc_title,
            'cn_title'   => $cn_title,
            'en_title'   => $en_title,
            'from_url'   => $row["url"],
            'from_site'  => $row["site"],
            'pic'        => $row["pic"] ?? '',
            'images'     => '[]',
            'verify'     => 1,
            'ctime'      => $ptime,
            'mtime'      => $ptime,
            'read_no'    => $row["read_no"] ?? 0,
            'virtual_no' => $row["virtual_no"] ?? 0,
        ];
        // 详情内容，如果没有 则显示描述
        $descs = [
            //'news_id'   => $item['id'],
            'ctime'       => $ptime,
            'cn_content'  => $cn_description,
            'cn_keywords' => implode(',', $cn_keywords),
            'en_content'  => $en_description,
            'en_keywords' => implode(',', $en_keywords),
            //'tc_keywords' => $tc_keywords,
            //'tc_content'  => $tc_content ?: $tc_description,
        ];


        // 执行添加
        DB::beginTransaction();
        try{
            // 执行添加
            $news_id = $newsDb->insertGetId($insert);
            // 重新组合
            $descs['news_id'] = $news_id;

            // 保存详情
            $descDb->insert($descs);

            // 更新链接
            // 完善请求链接
            $link = atwArticleLink($en_title, $news_id);
            $info = $newsDb->where('link', $link)->where('id', '!=', $news_id)->where('verify', '>=', 0)->first();
            if($info){
                throw new \Exception('该文章链接已经存在！');
            }
            $newsDb->where('id', $news_id)->update(['link' => $link]);

            // 保存栏目 以及 计算栏目数据
            foreach($_cateIds as $_cid){
                $_cates[] = ['cate_id' => $_cid, 'news_id' => $news_id, 'ctime' => $ptime];
            }
            if(!empty($_cates)){
                $cateDb->insert($_cates);
            }

            // 保存标签 以及 计算标签数据
            foreach($_tagIds as $_tid){
                $_tags[] = ['tag_id' => $_tid, 'news_id' => $news_id, 'ctime' => $ptime];
            }
            if(!empty($_tags)){
                $tagDb->insert($_tags);
            }

            // 增加标签
            if($_tagIds){
                foreach($_tagIds as $_tid){
                    (new SiteTag())->where('id', $_tid)->update(['number' => DB::raw("number+1")]);
                }
            }
            // 增加栏目
            if($_cateIds){
                foreach($_cateIds as $_cid){
                    (new SiteCate())->where('id', $_cid)->update(['number' => DB::raw("number+1")]);
                }
            }


            DB::commit();
        } catch(\Exception $e){
            DB::rollBack();

            return $this->showError($e->getMessage());
        }

        // 缓存操作
        $newsDb->deleteCacheShow($insert);
        $descDb->deleteCacheShow($descs);
        $cateDb->deleteCacheList($_cates);
        $tagDb->deleteCacheList($_tags);


        // TODO 添加到搜索引擎
        //$search = (new Xunsearch())->setDb('news');
        //$res    = $search->add($xun);


        return $news_id;
    }

    // 执行翻译  谷歌翻译
    protected function translate($text, $lang)
    {
        if(empty($text)){
            return '';
        }

        Log::info('执行翻译：'.$lang.' 内容：'.$text);
        $translate = new Translate();
        $result    = $translate->translateTo($text, $lang);

        return $result['text'] ?? '';
    }


    // 设置 cmd 标题
    protected function cmdTitle($title)
    {
        // 如果是Windows系统才执行
        if(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'){
            echo `title=$title`;
        }
    }

    // sql日志
    protected function sqlLog()
    {
        // 保存sql语句到日志中
        /*$queries = DB::getQueryLog();
        foreach($queries as $query){
            $sql = str_replace('?', '\'%s\'', $query['query']);
            $sql = vsprintf($sql, $query['bindings']);
            $log = 'SQL: '.$sql.'; [RunTime:'.$query['time'].'ms]';
            Log::info($log);
        }*/

        // 是否内存
        DB::flushQueryLog();
    }

    // 异步请求（有时候file_get_contents不能使用）
    protected function curlData($url, $method = 'get', $data = array(), $header = array())
    {
        // get 请求接口
        if(($method == "get") && $data){
            $url = $url.'?'.http_build_query($data);
        }


        $ch       = curl_init();
        $header[] = "Accept-Charset: utf-8";
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
        //curl_setopt($ch, CURLOPT_POSTFIELDS, $method == "get" ? http_build_query($data) : json_encode($data));

        // 请求方式
        if($method == "get"){
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
        } else{
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        }


        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, false);   // 显示返回的Header区域内容
        $temp = curl_exec($ch);
        curl_close($ch);

        return $temp;
    }

    // 过滤所有不需要的
    protected function filterSystem($title, $desc = '')
    {
        $filters = ["新冠", "COVID", "疫情", "病毒", "冠状", "疫苗", "确诊", "病例", "症状", "共产党", "中共", "环球", "卫星", "小程序", "重点关注", "习近平", "李强", "六四", "8964"];

        return $this->filterContent($title, $desc, $filters);
    }

    // 过滤不需要的来源 和 有详情的
    //  $filters 不需要的
    protected function filterContent($title, $desc, $filters = [])
    {
        $_is = false;
        if(empty($filters)){
            return $_is;
        }

        foreach($filters as $_it){
            if($title && (mb_strpos($title, $_it) !== false)){
                $_is = true;
                break;
            }
            if($desc && (mb_strpos($desc, $_it) !== false)){
                $_is = true;
                break;
            }
        }

        return $_is;
    }

    // 当前时间
    protected function getCurrentTime()
    {
        if(empty($this->ctime)){
            $this->ctime = time();
        }

        return $this->ctime;
    }

    // 获取所有的栏目 组合关键词列表
    //  $field:对比的字段，这里默认为中文
    protected function getCateKeywords($field = 'cn_keyword')
    {
        $cateDb = new SiteCate();
        $cates  = $cateDb->isCache(true)->getAll(['status' => 1], 'caiji_rank DESC');
        $cates  = is_object($cates) ? $cates->toArray() : $cates;

        // 整理
        $lists = [];
        foreach($cates as $_cate){
            $keywords    = explode(',', $_cate[$field]);
            $en_keywords = explode(',', $_cate['en_keyword']);
            $cn_keywords = explode(',', $_cate['cn_keyword']);
            $tc_keywords = explode(',', $_cate['tc_keyword']);
            foreach($keywords as $_index => $_keyword){
                if(empty($_keyword)){
                    continue;
                }
                // 组合
                //$lists[$_keyword] = ['id' => $_cate['id'], 'cn' => $cn_keywords[$_index] ?? '', 'en' => $en_keywords[$_index] ?? '', 'tc' => $tc_keywords[$_index] ?? '',];
                $lists[$_keyword] = ['id' => $_cate['id']];
            }
        }

        return $lists;
    }

    // 根据文章内容匹配到栏目
    protected function keywordToCate($cateKeywords, $content, $ctime, $isMultiple = false)
    {
        $cateIds = $cateData = $keywordS = [];  // 已经有了的栏目（避免一篇文章多次匹配同一个栏目）
        foreach($cateKeywords as $_keyword => $_cate){
            // 标签：关键词
            $_keyword = trim($_keyword);
            // 如果没有这个关键词
            if(strpos($content, $_keyword) === false){
                continue;
            }

            if(!in_array($_keyword, $keywordS)){
                $keywordS[] = $_keyword;      // 标签
            }
            // 如果这个栏目以及匹配了  则不在匹配这个栏目
            $_cateId = $_cate['id'];
            if(in_array($_cateId, $cateIds)){
                continue;
            }
            // 一篇文章多个栏目
            if($isMultiple){
                $cateData[] = ['cate_id' => $_cateId, 'status' => 1, 'ctime' => $ctime];
                $cateIds[]  = $_cateId;
            } else{
                // 一篇文章一个栏目
                if(empty($cateIds)){
                    $cateData[] = ['cate_id' => $_cateId, 'status' => 1, 'ctime' => $ctime];
                    $cateIds[]  = $_cateId;
                }
            }
        }

        // 如果没有分配到栏目，则分配到宏观里面
        if(empty($cateData)){
            //$cateData[] = ['cate_id' => 2, 'status' => 1, 'ctime' => $ctime];
            //$cateData[] = ['news_id' => $item['id'], 'cate_id' => 2, 'status' => 1, 'ctime' => $ctime];
        }

        return ['cate_ids' => $cateIds, 'keywords' => $keywordS];
    }

    // 根据文章内容匹配到标签
    protected function keywordToTag($cateKeywords, $cnKeywords, $enKeywords, $ctime)
    {
        // 组合标签
        $field  = 'cn_title';
        $tagIds = $cn_keywords = $en_keywords = $tc_keywords = [];

        // 根据提取的标签整理
        $hasKeywords = $cnKeywords ?: $enKeywords;
        if($hasKeywords){
            foreach($hasKeywords as $_kk => $_keyword){
                $cn_title = $cnKeywords[$_kk] ?: $this->translate($_keyword, 'cn');
                $en_title = $enKeywords[$_kk] ?: $this->translate($_keyword, 'en');
                $tc_title = $this->translate($_keyword, 'tc');
                // 查询 标签是否存在
                $_has = (new SiteTag())->where($field, $_keyword)->where('status', 1)->first();
                if(empty($_has)){
                    // 添加
                    $row   = ['en_title' => $en_title, 'cn_title' => $cn_title, 'tc_title' => $tc_title, 'status' => 1, 'ctime' => $ctime, 'mtime' => $ctime,];
                    $tagId = (new SiteTag())->insertGetId($row);
                } else{
                    $tagId = $_has->id;
                    // 更新标签
                    $_update = [];
                    if(empty($_has['cn_title'])){
                        $_update['cn_title'] = $cn_title;
                    }
                    if(empty($_has['en_title'])){
                        $_update['en_title'] = $en_title;
                    }
                    if(empty($_has['tc_title'])){
                        $_update['tc_title'] = $tc_title;
                    }
                    if($_update){
                        (new SiteTag())->where('id', $tagId)->update($_update);
                    }
                }

                // 去重
                if(in_array($tagId, $tagIds)){
                    continue;
                }

                // 组合
                $tagIds[]      = $tagId;
                $cn_keywords[] = $cn_title;
                $en_keywords[] = $en_title;
                $tc_keywords[] = $tc_title;
            }
        }

        // 根据栏目标签整理标签
        if(empty($hasKeywords) && $cateKeywords){
            foreach($cateKeywords as $_keyword){
                // 查询标签是否已经存在
                $_has = (new SiteTag())->where($field, $_keyword)->where('status', 1)->first();
                if(empty($_has)){
                    // 添加
                    // 进行翻译 中文 繁体
                    $cn_title = $this->translate($_keyword, 'cn');
                    $en_title = $this->translate($_keyword, 'en');
                    $tc_title = $this->translate($_keyword, 'tc');
                    $row      = ['en_title' => $en_title, 'cn_title' => $cn_title, 'tc_title' => $tc_title, 'status' => 1, 'ctime' => $ctime, 'mtime' => $ctime,];
                    $tagId    = (new SiteTag())->insertGetId($row);
                } else{
                    $tagId = $_has->id;
                    // 更新标签
                    $_update  = [];
                    $cn_title = $_has['cn_title'] ?: $this->translate($_keyword, 'cn');
                    $en_title = $_has['en_title'] ?: $this->translate($_keyword, 'en');
                    $tc_title = $_has['tc_title'] ?: $this->translate($_keyword, 'tc');
                    if(empty($_has['cn_title'])){
                        $_update['cn_title'] = $cn_title;
                    }
                    if(empty($_has['en_title'])){
                        $_update['en_title'] = $en_title;
                    }
                    if(empty($_has['tc_title'])){
                        $_update['tc_title'] = $tc_title;
                    }
                    if($_update){
                        (new SiteTag())->where('id', $tagId)->update($_update);
                    }
                }

                // 去重
                if(in_array($tagId, $tagIds)){
                    continue;
                }

                // 组合
                $tagIds[]      = $tagId;
                $cn_keywords[] = $cn_title;
                $en_keywords[] = $en_title;
                $tc_keywords[] = $tc_title;
            }
        }

        return ['tag_ids' => $tagIds, 'cn_keywords' => $cn_keywords, 'tc_keywords' => $tc_keywords, 'en_keywords' => $en_keywords,];
    }


    protected function keywordToCate2($cateKeywords, $content, $ctime, $isMultiple = false)
    {
        $cateIds = $cateData = $keywordS = [];  // 已经有了的栏目（避免一篇文章多次匹配同一个栏目）
        foreach($cateKeywords as $_keyword => $_cate){
            // 标签：关键词
            $_keyword = trim($_keyword);
            // 如果没有这个关键词
            if(strpos($content, $_keyword) === false){
                continue;
            }

            if(!in_array($_keyword, $keywordS)){
                $keywordS[] = $_keyword;      // 标签
            }
            // 如果这个栏目以及匹配了  则不在匹配这个栏目
            $_cateId = $_cate['id'];
            if(in_array($_cateId, $cateIds)){
                continue;
            }
            // 一篇文章多个栏目
            if($isMultiple){
                $cateData[] = ['cate_id' => $_cateId, 'status' => 1, 'ctime' => $ctime];
                $cateIds[]  = $_cateId;
            } else{
                // 一篇文章一个栏目
                if(empty($cateIds)){
                    $cateData[] = ['cate_id' => $_cateId, 'status' => 1, 'ctime' => $ctime];
                    $cateIds[]  = $_cateId;
                }
            }
        }

        // 如果没有分配到栏目，则分配到宏观里面
        if(empty($cateData)){
            //$cateData[] = ['cate_id' => 2, 'status' => 1, 'ctime' => $ctime];
            //$cateData[] = ['news_id' => $item['id'], 'cate_id' => 2, 'status' => 1, 'ctime' => $ctime];
        }


        // 组合标签
        $tagIds = $cn_keywords = $en_keywords = $tc_keywords = [];
        if($keywordS){
            $field = 'cn_title';
            foreach($keywordS as $_keyword){
                // 查询标签是否已经存在
                $_has = (new SiteTag())->where($field, $_keyword)->where('status', 1)->first();
                if(empty($_has)){
                    // 添加
                    // 进行翻译 中文 繁体
                    $cn_title = $this->translate($_keyword, 'cn');
                    $en_title = $this->translate($_keyword, 'en');
                    $tc_title = $this->translate($_keyword, 'tc');
                    $row      = ['en_title' => $en_title, 'cn_title' => $cn_title, 'tc_title' => $tc_title, 'status' => 1, 'ctime' => $ctime, 'mtime' => $ctime,];
                    $tagId    = (new SiteTag())->insertGetId($row);
                } else{
                    $tagId = $_has->id;
                    // 更新标签
                    $_update  = [];
                    $cn_title = $_has['cn_title'] ?: $this->translate($_keyword, 'cn');
                    $en_title = $_has['en_title'] ?: $this->translate($_keyword, 'en');
                    $tc_title = $_has['tc_title'] ?: $this->translate($_keyword, 'tc');
                    if(empty($_has['cn_title'])){
                        $_update['cn_title'] = $cn_title;
                    }
                    if(empty($_has['en_title'])){
                        $_update['en_title'] = $en_title;
                    }
                    if(empty($_has['tc_title'])){
                        $_update['tc_title'] = $tc_title;
                    }
                    if($_update){
                        (new SiteTag())->where('id', $tagId)->update($_update);
                    }
                }

                // 组合
                $tagIds[]      = $tagId;
                $cn_keywords[] = $cn_title;
                $en_keywords[] = $en_title;
                $tc_keywords[] = $tc_title;
            }
        }

        return ['cate_ids' => $cateIds, 'tag_ids' => $tagIds, 'cn_keywords' => $cn_keywords, 'tc_keywords' => $tc_keywords, 'en_keywords' => $en_keywords,];
    }


    // 去除 来源
    protected function removeOrigin($brief)
    {
        $lastChar = mb_substr($brief, -1, 1, 'UTF-8');
        $lastPos  = '';
        if($lastChar == ')'){
            $lastPos = mb_strrpos($brief, '(', 0, 'UTF-8');
            if($lastPos === false){
                $lastPos = mb_strrpos($brief, '（', 0, 'UTF-8');
            }
        } elseif($lastChar == '）'){
            $lastPos = mb_strrpos($brief, '（', 0, 'UTF-8');
            if($lastPos === false){
                $lastPos = mb_strrpos($brief, '(', 0, 'UTF-8');
            }
        }
        if($lastPos){
            $brief = mb_substr($brief, 0, $lastPos, 'UTF-8');
        }

        return $brief;
    }

    // 读取目录
    public function readDir(string $path, $is_one = true, $return_path = true)
    {
        $result = [];
        if(!is_dir($path)){
            return $result;
        }
        $open = opendir($path);
        if(!$open){
            return $result;
        }
        while(($v = readdir($open)) !== false){
            if('.' == $v || '..' == $v){
                continue;
            }
            $_path = $path.'/'.$v;
            $item  = $return_path ? $path.'/'.$v : $v;
            if(is_file($item)){
                $result[] = $item;
                continue;
            }
            if($is_one){
                $result[] = $item;
                continue;
            }
            // 如果不是获取第一级目录 则 继续读取下级目录
            if(empty($is_one)){
                //$result[$path][] = $this->readDir($_path);
                $result[] = $this->readDir($_path);
            }
        }

        closedir($open);

        return $result;
    }


    // 以前的执行
    public function _handle()
    {
        // 输出信息
        $this->line('准备各种颜色的输出信息');
        $this->line('line <info>info</info> <error>error</error> <comment>comment</comment> <question>question</question>');
        $this->info('This is info');
        $this->error('This is error');
        $this->comment('This is comment');
        $this->question('This is question');
        $this->line("1\n2\n");

        // 在 storage/app/logs中
        // Log::info('command:name命令执行 | 这里是命令任务');

        return true; // return 语句是不会展示出来的
    }

}
